

#include <ctime>
#include "../include/Iec104ServiceManager.h"
#include "CConfigManager.h"
#include "MappingRelationManager.h"
#include "CLogger.h"

CIec104ServiceManager::CIec104ServiceManager(){

}

CIec104ServiceManager::~CIec104ServiceManager(){

}

void CIec104ServiceManager::init(std::shared_ptr<CConfigManager> cm, std::shared_ptr<DataCenterManager> dcm)
{
    c_cm = cm;
    c_dcm = dcm;

    get_iec104_ca();
}

//查询实时数据
int CIec104ServiceManager::get_dc_realtime_data(int& ca, ST_APDU_POINT_DATA& stApduPtData, ST_APDU_MEASUREDVAL_DATA& stApduMearData, ST_APDU_INTERRTOTAL_DATA& stCounterIntertData)
{
    CLogger::getInstance()->log_d("get_dc_realtime_data:begin.");

    auto lstDevs= DataCenterManager::getInstance()->get_dc_devs();
    if (lstDevs.size() == 0)
    {
        CLogger::getInstance()->LOG_I("get_dc_realtime_data:datacenter has no register devs.");
        return 0;
    }

    std::list<ST_REALTIME_QUERY_DEV_RSP> lstRealtimeQueryRsp = c_dcm->dc_query_realtime_datas(lstDevs);   //从数据中心查询实时数据
    if (lstRealtimeQueryRsp.size() >0)
    {
        for (auto itr = lstRealtimeQueryRsp.begin(); itr != lstRealtimeQueryRsp.end(); itr++)
        {
            std::string dev = itr->dev;
            for (auto itd = itr->lstQueryDataItems.begin(); itd != itr->lstQueryDataItems.end(); itd++)
            {
                auto  pst104Obj = CMappingRelationManager::getInstance()->get_iec104Obj_with_dev_ptname(dev, itd->name);
                if (pst104Obj)
                {
                    CLogger::getInstance()->log_i("dc_realtime_data: ptname=%s,val=%s",itd->name.c_str(),itd->val.c_str());
                    iec104Obj_classify(itd->val, itd->timestamp,pst104Obj, stApduPtData, stApduMearData,stCounterIntertData);
                }
                else{
                    CLogger::getInstance()->LOG_W("dev=%s point=%s not find 104 object.",dev.c_str(),itd->name.c_str());
                }
            }
        }
    }
    else{
        CLogger::getInstance()->LOG_I("get_dc_realtime_data:datacenter has no realtime data.");
    }

    return 1;
}

int CIec104ServiceManager::get_report_data(std::string& dev, std::list<ST_CHANGE_REPORT_DATAPT>& lstChangeReportPts, int& ca, ST_APDU_POINT_DATA& stApduPtData, 
                                           ST_APDU_MEASUREDVAL_DATA& stApduMearData, ST_APDU_INTERRTOTAL_DATA&  stCounterInterrData)
{
    CLogger::getInstance()->log_d("get_report_data:begin.");

    ca = c_ca;

    for (auto itct = lstChangeReportPts.begin(); itct != lstChangeReportPts.end(); itct++)
    {
        auto  pst104Obj = CMappingRelationManager::getInstance()->get_iec104Obj_with_dev_ptname(dev, itct->name);
        if (pst104Obj)
        {
            iec104Obj_classify(itct->val, itct->timestamp, pst104Obj, stApduPtData, stApduMearData,stCounterInterrData);
            CLogger::getInstance()->log_d("get_report_data: dev=%s,ptname=%s,val=%s", dev.c_str(), itct->name.c_str(), itct->val.c_str());
        }
        else{
            CLogger::getInstance()->LOG_W("get_report_data(point_name=%s)  not find 104obj.",itct->name.c_str());
        }
    }
    CLogger::getInstance()->log_d("get_report_data:end.");

    return 1;
}

void CIec104ServiceManager::iec104Obj_classify(std::string& val, std::string& timestamp, std::shared_ptr<ST_104_INFO_OBJECT> st104Obj,
                                               ST_APDU_POINT_DATA& stApduPtData, ST_APDU_MEASUREDVAL_DATA& stApduMearData, ST_APDU_INTERRTOTAL_DATA& stApduCounterInterrData)
{
    switch (st104Obj->info_type)
    {
    case M_SP_NA_1:     //单点信息
    case M_SP_TA_1:     //带时标的单点信息
    case M_DP_NA_1:     //双点信息
    case M_DP_TA_1:     //带时标的双点信息
    case M_SP_TB_1:     //带CP56Time2a时标的单点信息
    case M_DP_TB_1:     //带CP56Time2a时标的双点信息
    {
        ST_IEC104_PTVAL  stPtVal;
        
        stPtVal.ioa = st104Obj->info_addr;
        stPtVal.val = atoi(val.c_str());
        stPtVal.acq_time = get_cp56_timestamp(timestamp);
        stApduPtData.ti = st104Obj->info_type;
        stApduPtData.lstObjs.push_back(stPtVal);
    }
    break;
    case M_ME_NA_1:     //测量值，归一化值
    case M_ME_TA_1:     //测量值，带时标归一化值
    case M_ME_NB_1:     //测量值，标度化值
    case M_ME_TB_1:     //测量值，带时标标度化值
    case M_ME_NC_1:     //测量值，短浮点数
    case M_ME_TC_1:     //测量值，带时标短浮点数
    case M_ME_TD_1:     //测量值，带CP56Time2a的标度化值
    case M_ME_TE_1:     //测量值，带CP56Time
    {
        ST_IEC104_MEAR_VAL  stMearVal;
        stMearVal.ioa = st104Obj->info_addr;
        stMearVal.fval = atof(val.c_str());
        stMearVal.acq_time = get_cp56_timestamp(timestamp);
        stApduMearData.ti = st104Obj->info_type;
        stApduMearData.lstObjs.push_back(stMearVal);
    }
    break;
    case M_IT_NA_1:
    case M_IT_TA_1:
    case M_IT_TB_1:
    {
        int64_t  totalv = atoll(val.c_str());
        ST_IEC104_INTERTOTAL_VAL  stCounterVal;
        stCounterVal.ioa = st104Obj->info_addr;
        memcpy(stCounterVal.totalval->encodedValue, &totalv, 5);   //BinaryCounterReading  定义了5字节
        stCounterVal.acq_time = get_cp56_timestamp(timestamp);
        stApduCounterInterrData.ti = st104Obj->info_type;
        stApduCounterInterrData.lstObjs.push_back(stCounterVal);
    }
    break;
    default:
        CLogger::getInstance()->log_d("iec104Obj_classify:unsurported infotype.");
        break;
    }
}
CP56Time2a CIec104ServiceManager::get_cp56_timestamp(std::string& strtime)
{
    CLogger::getInstance()->log_d("get_cp56_timestamp:%s",strtime.c_str());

    std::string::size_type  fpos= strtime.find('+'); //2023-02-23T14:58:57.493+0800
    std::string stdtime = strtime.substr(0, fpos - 4);

    CP56Time2a  cp56Time =(CP56Time2a)malloc(sizeof(struct sCP56Time2a));  //在外部释放

    struct tm  timeinfo;
    strptime(stdtime.c_str(), "%Y-%m-%dT%H:%M:%S", &timeinfo);

    CP56Time2a_setYear(cp56Time, timeinfo.tm_year -2000);
    CP56Time2a_setMonth(cp56Time, timeinfo.tm_mon + 1);
    CP56Time2a_setDayOfMonth(cp56Time, timeinfo.tm_mday);
    CP56Time2a_setHour(cp56Time, timeinfo.tm_hour);
    CP56Time2a_setSecond(cp56Time, timeinfo.tm_sec);

    return cp56Time;
}

void CIec104ServiceManager::get_iec104_ca()
{
    auto iec104_rule = c_cm->get_iec104_rules();
    if (nullptr == iec104_rule)
    {
        CLogger::getInstance()->log_d("get_iec104_ca:no iec104 rules.");
        return ;
    }
    if (iec104_rule->size() == 0)
    {
        CLogger::getInstance()->log_d("get_iec104_ca:iec104 rules num is 0.");
        return ;
    }
  
    auto it104 = iec104_rule->begin();
    c_ca = it104->second.asdu_addr;

    CLogger::getInstance()->log_d("get_iec104_ca =%d end.",c_ca);
}